package game.module.ddz.processor;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import game.RoomServer;
import game.common.PlayingRoleMsgProcessor;
import game.entity.PlayingRole;
import game.module.ddz.DdzConstants;
import game.module.ddz.bean.DdzRound;
import game.module.ddz.bean.DdzStatus;
import game.module.ddz.logic.DdzAlgorithm;
import game.module.ddz.logic.DdzDataManager;
import game.module.ddz.logic.DdzLogic;
import game.session.SessionManager;
import lion.common.ArrayUtility;
import lion.common.MsgCodeAnn;
import lion.netty4.message.MyRequestMessage;
import lion.netty4.message.RequestMessageRaw;
import lion.netty4.message.RequestProtoMessage;
import lua.LuaMessageDdz.C2SDdzChupai;
import lua.LuaMessageDdz.PlayerPaiList;
import lua.LuaMessageDdz.PushDdzChupai;
import lua.LuaMessageDdz.PushDdzRoundEnd;
import lua.LuaMessageDdz.RoundScore;
import lua.LuaMessageDdz.S2CDdzChupai;
import lua.LuaMessageLogin.S2ErrorCode;

@MsgCodeAnn(msgcode = C2SDdzChupai.id, accessLimit = 500)
public class DdzChuPaiProcessor extends PlayingRoleMsgProcessor {

	private static Logger logger = LoggerFactory.getLogger(DdzChuPaiProcessor.class);

	@Override
	public void process(PlayingRole playingRole, RequestMessageRaw request) throws Exception {
		C2SDdzChupai reqMsg = C2SDdzChupai.parse(request);
		byte[] pai_list = reqMsg.pai;
		int playerId = playingRole.getId();
		logger.info("ddz chu pai,playerId={},pai_list={}", playerId, pai_list);
		// 是否加倍
		final DdzRound ddzRound = DdzDataManager.getInstance().getDdzRoom(playerId);
		if (!ddzRound.isJiaBei()) {
			S2ErrorCode respMsg = new S2ErrorCode(213);
			playingRole.writeAndFlush(respMsg.build(playingRole.alloc()));
			return;
		}
		// 当前是否我的回合
		S2CDdzChupai respMsg = new S2CDdzChupai((short) 0);
		int chuPaiIndex = ddzRound.getChuPaiIndex();
		int myIndex = ddzRound.getPlayerIds().indexOf(playerId);
		if (myIndex != chuPaiIndex) {
			// S2ErrorCode respMsg = new S2ErrorCode(205);
			respMsg.is_success = 1;
			playingRole.writeAndFlush(respMsg.build(playingRole.alloc()));
			return;
		}
		// 是否是我的牌
		List<Byte> myCards = ddzRound.getCards().get(myIndex);
		for (byte aChuPai : pai_list) {
			if (!myCards.contains(aChuPai)) {
				// S2ErrorCode respMsg = new S2ErrorCode(204);
				respMsg.is_success = 2;
				playingRole.writeAndFlush(respMsg.build(playingRole.alloc()));
				return;
			}
		}
		// 一圈打完不能出空牌
		Integer validChupaiIndex = ddzRound.getValidChupaiIndex();
		if (validChupaiIndex != null && myIndex == validChupaiIndex) {
			if (pai_list.length == 0) {
				respMsg.is_success = 3;
				playingRole.writeAndFlush(respMsg.build(playingRole.alloc()));
				return;
			}
		}
		// 牌大小比较
		if (pai_list.length > 0) {
			// 从大到小排序
			DdzAlgorithm.getInstance().SortCardList(pai_list, (byte) pai_list.length, DdzConstants.ST_ORDER);
			// 出牌是否有效
			byte isPaiValid = DdzAlgorithm.getInstance().GetCardType(pai_list, (byte) pai_list.length);
			if (isPaiValid == DdzConstants.CT_ERROR) {
				// S2ErrorCode respMsg = new S2ErrorCode(206);
				respMsg.is_success = 4;
				playingRole.writeAndFlush(respMsg.build(playingRole.alloc()));
				return;
			}
			// 一圈打完
			if (validChupaiIndex != null && myIndex == validChupaiIndex) {
				// nothing
			} else {
				// 是否比上次的出牌大
				byte[] last_chupai = ddzRound.getValid_chuPai();
				if (last_chupai != null && last_chupai.length > 0) {
					boolean isBigger = DdzAlgorithm.getInstance().CompareCard(last_chupai, pai_list,
							(byte) last_chupai.length, (byte) pai_list.length);
					if (!isBigger) {
						// S2ErrorCode respMsg = new S2ErrorCode(207);
						respMsg.is_success = 5;
						playingRole.writeAndFlush(respMsg.build(playingRole.alloc()));
						return;
					}
				}
			}
			// 是否炸弹
			if (isPaiValid == DdzConstants.CT_BOMB_CARD || isPaiValid == DdzConstants.CT_MISSILE_CARD) {
				short oldScore = ddzRound.getRoundScore();
				oldScore *= 2;
				ddzRound.setRoundScore(oldScore);
			}
		}

		// do
		if (pai_list.length > 0) {
			ddzRound.setValidChupaiIndex(myIndex);
			ddzRound.setValid_chuPai(pai_list);
		}
		chuPaiIndex++;
		if (chuPaiIndex >= 3) {
			chuPaiIndex = 0;
		}
		ddzRound.setChuPaiIndex(chuPaiIndex);
		// 记录出牌次数
		if (pai_list.length > 0) {
			Map<Integer, Integer> chupaiCount = ddzRound.getChuPaiCount();
			if (chupaiCount == null) {
				chupaiCount = new HashMap<>();
				ddzRound.setChuPaiCount(chupaiCount);
			}
			Integer myValidChuPaiCount = chupaiCount.get(myIndex);
			if (myValidChuPaiCount == null) {
				chupaiCount.put(myIndex, 1);
			} else {
				chupaiCount.put(myIndex, myValidChuPaiCount + 1);
			}
		}
		// 扣掉手牌
		for (byte aChuPai : pai_list) {
			int aIndex = myCards.indexOf(aChuPai);
			myCards.remove(aIndex);
		}
		// ret
		playingRole.writeAndFlush(respMsg.build(playingRole.alloc()));
		// push
		PushDdzChupai pushMsg = new PushDdzChupai();
		pushMsg.chupai_player_index = (short) myIndex;
		pushMsg.pai = pai_list;
		List<Integer> playerIds = ddzRound.getPlayerIds();
		for (Integer aPlayerId : playerIds) {
			PlayingRole pr = SessionManager.getInstance().getPlayer(aPlayerId);
			if (pr != null && pr.isChannelActive()) {
				pr.writeAndFlush(pushMsg.build(pr.alloc()));
			}
		}
		// 获胜判断
		if (myCards.size() == 0) {
			ddzRound.setDdzStatus(DdzStatus.ROUND_END);
			short winnerScore = ddzRound.getRoundScore();
			PushDdzRoundEnd roundEndMsg = new PushDdzRoundEnd();
			int diZhuIndex = ddzRound.getDiZhuIndex();
			boolean isDiZhuWin = myIndex == diZhuIndex;
			roundEndMsg.is_dizhu_win = isDiZhuWin;
			int diZhuPlayerId = playerIds.get(diZhuIndex);
			roundEndMsg.score_list = new RoundScore[playerIds.size()];
			// 判断春天类型
			byte spring_type = getSpringType(diZhuIndex, ddzRound.getChuPaiCount());
			roundEndMsg.spring_type = spring_type;
			int i = 0;
			for (Integer aPlayerId : playerIds) {
				int myScore = getPlayerScore(spring_type, winnerScore, diZhuIndex, i, ddzRound.getJiaBeiMap());
				if (aPlayerId == diZhuPlayerId) {
					// myScore = winnerScore * (playerIds.size() - 1);
					if (!isDiZhuWin) {
						myScore = -myScore;
					}
				} else {
					if (isDiZhuWin) {
						myScore = -myScore;
					}
				}
				roundEndMsg.score_list[i++] = new RoundScore((short) (myScore), aPlayerId);
			}
			// 剩余卡牌信息
			roundEndMsg.pai_list = new PlayerPaiList[playerIds.size()];
			i = 0;
			for (i = 0; i < ddzRound.getCards().size(); i++) {
				List<Byte> cardList = ddzRound.getCards().get(i);
				roundEndMsg.pai_list[i] = new PlayerPaiList();
				roundEndMsg.pai_list[i].pai = ArrayUtility.toByteArray(cardList);
			}
			for (Integer aPlayerId : playerIds) {
				PlayingRole pr = SessionManager.getInstance().getPlayer(aPlayerId);
				if (pr != null && pr.isChannelActive()) {
					pr.writeAndFlush(roundEndMsg.build(pr.alloc()));
				}
			}
			// 下一轮发牌
			if (ddzRound.getRoundCount() < ddzRound.getRoundSum()) {
				RoomServer.executorService.schedule(new Runnable() {
					@Override
					public void run() {
						DdzLogic.getInstance().nextRound(ddzRound);
					}
				}, 5, TimeUnit.SECONDS);
			} else {
				// TODO 最终结算
				for (Integer aPlayerId : playerIds) {
					DdzDataManager.getInstance().removePlayer(aPlayerId);
				}
				ddzRound.setCards(null);
				ddzRound.setDi(null);
				ddzRound.setJiaoDiZhuIndex(null);
				ddzRound.setPlayerIds(null);
				ddzRound.setRoundCount(null);
				ddzRound.setLoopCount(0);
				ddzRound.setLastJiaoScore(null);
				ddzRound.setLastJiaoIndex(null);
				ddzRound.setDiZhuIndex(null);
				ddzRound.setChuPaiIndex(null);
				ddzRound.setValid_chuPai(null);
				ddzRound.setValidChupaiIndex(null);
				ddzRound.setCancelQiangSet(null);
				ddzRound.setCancelFanQiangSet(null);
				ddzRound.setJiaBeiMap(null);
			}
		}
	}

	private byte getSpringType(int diZhuIndex, Map<Integer, Integer> chuPaiCount) {
		// 是否春天
		if (chuPaiCount.size() == 1 && chuPaiCount.containsKey(diZhuIndex)) {
			return 1;
		}
		// 是否反春天
		if (!chuPaiCount.containsKey(diZhuIndex)
				|| (chuPaiCount.containsKey(diZhuIndex) && chuPaiCount.get(diZhuIndex) == 1)) {
			return 2;
		}
		return 0;
	}

	private int getPlayerScore(byte spring_type, short winnerScore, int diZhuIndex, int playerIndex,
			Map<Integer, Integer> jiaBeiMap) {
		int retScore = 0;
		if (spring_type > 0) {
			winnerScore *= 2;
		}
		if (playerIndex != diZhuIndex) {
			retScore = winnerScore * jiaBeiMap.get(playerIndex);
		} else {
			for (Integer aRate : jiaBeiMap.values()) {
				retScore += winnerScore * aRate;
			}
		}
		return retScore;
	}

	@Override
	public void processProto(PlayingRole playingRole, RequestProtoMessage request) throws Exception {
		// TODO Auto-generated method stub

	}

	@Override
	public void processWebsocket(PlayingRole playingRole, MyRequestMessage request) throws Exception {
		// TODO Auto-generated method stub

	}

}
